home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 August: Tool Chest / Dev.CD Aug 00 TC Disk 2.toast / pc / sample code / quicktime / all macintosh / effects / samplemakeeffectmovie / makeeffectmovie.c < prev    next >
Encoding:
Text File  |  2000-06-23  |  19.2 KB  |  599 lines

  1. //////////
  2. //
  3. //    File:        MakeEffectMovie.c
  4. //
  5. //    Contains:    QuickTime video effect support for QuickTime movies.
  6. //                This file is used for BOTH MacOS and Windows.
  7. //
  8. //    Written by:    Tim Monroe
  9. //                Based (heavily!) on the previous MakeEffectMovie code written by Sam Bushell,
  10. //                which was based on ConvertToMovie.c from ConvertToMovie Jr. sample code.
  11. //
  12. //    Copyright:    © 1997-1999 by Apple Computer, Inc., all rights reserved.
  13. //
  14. //    Change History (most recent first):
  15. //
  16. //       <6>         03/03/99    rtm        added support for MakeImageDescriptionForEffect (QT 4.0 and later)
  17. //       <5>         03/12/98    rtm        added global flag gDoneWithDialog to fix Windows dialog box problems
  18. //       <4>         02/28/98    rtm        revised event/message handling following QTShowEffect.c
  19. //       <3>         01/08/98    rtm        sync'ed with latest code from Sam: reworked QTEffects_GetFirstVideoTrackInMovie
  20. //                                    to use GetMovieIndTrackType and fixed time scale setting code; added global flag
  21. //                                    gCopyMovieMedia and menu commands to set that flag
  22. //       <2>         11/21/97    rtm        factored out QTEffects_GetFirstVideoTrackInMovie;
  23. //                                    reworked event-loop processing: changed QTEffects_MakeEffectMovieForSources into
  24. //                                    QTEffects_DisplayDialogForSources and QTEffects_RespondToDialogSelection.
  25. //       <1>         11/06/97    rtm        first file; integrated existing code with shell framework;
  26. //                                    added endian macros where appropriate
  27. //       
  28. //    This application takes the video tracks from zero, one, or two movies 
  29. //    and creates a new movie with an effects track for them.
  30. //
  31. //    Try it out: drag two short movies of the same size onto the application icon.
  32. //  The QuickTime effects dialog will appear and you can select an effect to transition
  33. //    from the first movie to the second. Or, drag a single movie onto the application icon
  34. //    and you'll get an effects dialog for one-source effects.
  35. //
  36. //    You can also launch the application and choose the Make Effect Movie menu command in
  37. //    the Test menu. You'll get a file-opening dialog box for each movie you want to apply
  38. //    the effects to. Just hit Cancel in the first dialog box to get zero-source effects (like fire).
  39. //
  40. //////////
  41.  
  42. // TO DO:
  43. // + copy sound tracks from original movie(s); add tweening of sound tracks as effect progresses
  44.  
  45. // header files
  46. #include "MakeEffectMovie.h"
  47.  
  48. // global variables
  49. QTParameterDialog            gEffectsDialog = 0L;            // identifier for the standard parameter dialog box
  50. QTAtomContainer                gEffectSample = NULL;            // effects sample
  51. QTAtomContainer                gEffectList = NULL;
  52. PicHandle                    gPosterA = NULL;
  53. PicHandle                    gPosterB = NULL;
  54. Movie                        gSrcMovies[kMaxNumSources] = {NULL, NULL};
  55. Track                        gSrcTracks[kMaxNumSources] = {NULL, NULL};
  56. UInt16                        gSpecCount = 0;        
  57. Boolean                        gCopyMovieMedia = false;        // should we copy the movie media into the new effects movie?
  58. Boolean                        gDoneWithDialog = false;        // are we done using the effects parameters dialog box?
  59.  
  60.  
  61. //////////
  62. //
  63. // QTEffects_GetFirstVideoTrackInMovie
  64. // Return, through the theTrack parameter, the first video track in the specified movie.
  65. //
  66. // Actually, we look for the first track that has the kCharacteristicCanSendVideo characteristic,
  67. // so we can apply effects to MPEG or QD3D tracks as well.
  68. //
  69. // If no such track is found, return invalidTrack as the function result.
  70. //
  71. //////////
  72.  
  73. OSErr QTEffects_GetFirstVideoTrackInMovie (Movie theMovie, Track *theTrack)
  74. {
  75.     *theTrack = GetMovieIndTrackType(theMovie, 1, kCharacteristicCanSendVideo, movieTrackCharacteristic | movieTrackEnabledOnly);
  76.     
  77.     if (*theTrack == NULL)
  78.         return(invalidTrack);
  79.         
  80.     return(noErr);
  81. }
  82.  
  83.  
  84. //////////
  85. //
  86. // QTEffects_DisplayDialogForSources
  87. // Display the standard effects parameters dialog box for the movies passed in.
  88. //
  89. //////////
  90.  
  91. OSErr QTEffects_DisplayDialogForSources (FSSpec *theSpecList, UInt16 theSpecCount)
  92. {
  93.     OSErr                    myErr = noErr;
  94.     UInt16                    myMovieIter;
  95.     
  96.     // make sure that there aren't too many sources
  97.     if (theSpecCount > kMaxNumSources) {
  98.         myErr = paramErr;
  99.         goto bail;
  100.     }
  101.     
  102.     // assign source count to a global, so QTEffects_RespondToDialogSelection has access to it
  103.     gSpecCount = theSpecCount;        
  104.     
  105.     // open the source movies, get movies from them, and get the first video track from each movie
  106.     for (myMovieIter = 0; myMovieIter < theSpecCount; myMovieIter++) {
  107.         short    myRefNum;
  108.         
  109.         // open a movie file using the FSSpec and create a movie from that file
  110.         myErr = OpenMovieFile(&theSpecList[myMovieIter], &myRefNum, 0);
  111.         BailError(myErr);
  112.         
  113.         myErr = NewMovieFromFile(&gSrcMovies[myMovieIter], myRefNum, NULL, NULL, newMovieActive, NULL);
  114.         BailError(myErr);
  115.         
  116.         SetMoviePlayHints(gSrcMovies[myMovieIter], hintsHighQuality, hintsHighQuality);
  117.  
  118.         // we're done with the movie file, so close it
  119.         CloseMovieFile(myRefNum);
  120.         
  121.         // find the first video track in the source movie
  122.         myErr = QTEffects_GetFirstVideoTrackInMovie(gSrcMovies[myMovieIter], &gSrcTracks[myMovieIter]);
  123.         BailError(myErr);
  124.     }
  125.     
  126.     // ask the user to select an effect
  127.  
  128.     myErr = QTNewAtomContainer(&gEffectSample);
  129.     BailError(myErr);
  130.     
  131.     myErr = QTGetEffectsList(&gEffectList, theSpecCount, theSpecCount, 0);
  132.     BailError(myErr);
  133.     
  134.     myErr = QTCreateStandardParameterDialog(gEffectList, gEffectSample, 0, &gEffectsDialog);
  135.     BailError(myErr);
  136.     
  137.     // insert poster frames into dialog
  138.     if (gSrcTracks[0] != NULL) {
  139.         gPosterA = GetTrackPict(gSrcTracks[0], GetMoviePosterTime(gSrcMovies[0]));
  140.         if (gPosterA != NULL) {
  141.             QTParamPreviewRecord            myPreviewRecord;
  142.  
  143.             myPreviewRecord.sourcePicture = gPosterA;
  144.             myPreviewRecord.sourceID = 1;
  145.             myErr = QTStandardParameterDialogDoAction(gEffectsDialog, pdActionSetPreviewPicture, &myPreviewRecord);
  146.         }
  147.     }
  148.  
  149.     if (gSrcTracks[1] != NULL) {
  150.         gPosterB = GetTrackPict(gSrcTracks[1], GetMoviePosterTime(gSrcMovies[1]));
  151.         if (gPosterB != NULL) {
  152.             QTParamPreviewRecord            myPreviewRecord;
  153.  
  154.             myPreviewRecord.sourcePicture = gPosterB;
  155.             myPreviewRecord.sourceID = 2;
  156.             myErr = QTStandardParameterDialogDoAction(gEffectsDialog, pdActionSetPreviewPicture, &myPreviewRecord);
  157.         }
  158.     }
  159.     
  160.     // now, the frontmost window is the standard effects parameter dialog box;
  161.     // on the Mac, we call QTEffects_HandleEffectsDialogEvents in our main event loop
  162.     // to find and process events targeted at the effects parameter dialog box; on Windows,
  163.     // we need to use a different strategy: we install a modeless dialog callback procedure
  164.     // that is called internally by QTML
  165.  
  166. #if TARGET_OS_WIN32
  167.     gDoneWithDialog = false;
  168.     
  169.     // force the dialog box to be drawn
  170.     {
  171.         EventRecord            myEvent = {0};
  172.         
  173.         QTEffects_EffectsDialogCallback(&myEvent, FrontWindow(), 0);
  174.     }
  175.     
  176.     SetModelessDialogCallbackProc(FrontWindow(), (QTModelessCallbackUPP)QTEffects_EffectsDialogCallback);
  177.     QTMLSetWindowWndProc(FrontWindow(), QTEffects_CustomDialogWndProc);
  178. #endif
  179.     
  180. bail:
  181.     return(myErr);
  182. }
  183.  
  184.  
  185. //////////
  186. //
  187. // QTEffects_RespondToDialogSelection
  188. // If theErr is codecParameterDialogConfirm, make an effects movie.
  189. // If theErr is userCanceledErr, do any necessary clean up.
  190. //
  191. //////////
  192.  
  193. void QTEffects_RespondToDialogSelection (OSErr theErr)
  194. {
  195.     short                    myMovieRefNum = 0;
  196.     short                    myResID = movieInDataForkResID;
  197.     Boolean                    myDialogWasCancelled = false;
  198.     OSType                    myEffectCode;
  199.     Fixed                    videoTrackFXWidth, videoTrackFXHeight;
  200.     TimeScale                myMovieTimeScale = 600; 
  201.     TimeValue                myEffectDuration = 0;
  202.     TimeValue                mySampleTime = 0;
  203.     StandardFileReply        myReply;
  204.     Movie                    myDestMovie = NULL;
  205.     Track                    videoTracks[kMaxNumSources] = {NULL, NULL};
  206.     Track                    videoTrackFX = NULL;
  207.     Media                    videoMediaFX = NULL;
  208.     UInt16                    myMovieIter;
  209.     long                    myFlags = createMovieFileDeleteCurFile | createMovieFileDontCreateResFile;
  210.     OSErr                    myErr = noErr;
  211.     
  212.     // standard parameter box has been dismissed, so remember that fact
  213.     gEffectsDialog = 0L;
  214.  
  215.     myDialogWasCancelled = (theErr == userCanceledErr);
  216.  
  217.     // we're finished with the effect list and movie posters    
  218.     QTDisposeAtomContainer(gEffectList);
  219.     
  220.     if (gPosterA != NULL)
  221.         KillPicture(gPosterA);
  222.         
  223.     if (gPosterB != NULL)
  224.         KillPicture(gPosterB);
  225.     
  226.     if (myDialogWasCancelled)
  227.         goto bail;
  228.     
  229.     // add atoms naming the sources to gEffectSample
  230.     {
  231.         long    myLong;
  232.         
  233.         if (gSpecCount >= 1) {
  234.             myLong = EndianU32_NtoB(kSourceOneName);
  235.             QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 1, 0, sizeof(myLong), &myLong, NULL);
  236.         }
  237.         
  238.         if (gSpecCount >= 2) {
  239.             myLong = EndianU32_NtoB(kSourceTwoName);
  240.             QTInsertChild(gEffectSample, kParentAtomIsContainer, kEffectSourceName, 2, 0, sizeof(myLong), &myLong, NULL);
  241.         }
  242.     }
  243.     
  244.     // extract the 'what' atom to find out what kind of effect it is
  245.     {
  246.         QTAtom            myEffectAtom;
  247.         QTAtomID        myEffectAtomID;
  248.         long            myEffectCodeSize;
  249.         Ptr                myEffectCodePtr;
  250.  
  251.         myEffectAtom = QTFindChildByIndex(gEffectSample, kParentAtomIsContainer, kParameterWhatName, kParameterWhatID, &myEffectAtomID);
  252.         
  253.         myErr = QTLockContainer(gEffectSample);
  254.         BailError(myErr);
  255.  
  256.         myErr = QTGetAtomDataPtr(gEffectSample, myEffectAtom, &myEffectCodeSize, &myEffectCodePtr);
  257.         BailError(myErr);
  258.  
  259.         if (myEffectCodeSize != sizeof(OSType)) {
  260.             myErr = paramErr;
  261.             goto bail;
  262.         }
  263.         
  264.         myEffectCode = *(OSType *)myEffectCodePtr;        // "tsk"
  265.         myEffectCode = EndianU32_BtoN(myEffectCode);    // because the data is read from an atom container
  266.         
  267.         myErr = QTUnlockContainer(gEffectSample);
  268.         BailError(myErr);
  269.     }
  270.  
  271.     // ask the user for the name of the new movie file
  272.     StandardPutFile("\pSave effect movie file as:", "\pUntitled.mov", &myReply);
  273.     if (!myReply.sfGood)
  274.         goto bail;                // deal with user cancelling
  275.  
  276.     // create a movie file for the destination movie
  277.     myErr = CreateMovieFile(&myReply.sfFile, FOUR_CHAR_CODE('TVOD'), smSystemScript, myFlags, &myMovieRefNum, &myDestMovie);
  278.     BailError(myErr);
  279.     
  280.     // copy the user data and settings from the source to the destination movie;
  281.     // these settings include information like user data
  282.     if (gSpecCount > 0)
  283.         CopyMovieSettings(gSrcMovies[0], myDestMovie);
  284.     
  285.     // convert all the movies to have a common time scale;
  286.     // we pick the largest time scale out of all the source movies, with a minimum of 600
  287.     myMovieTimeScale = 600;
  288.     for (myMovieIter = 0; myMovieIter < gSpecCount; myMovieIter++) {
  289.         if (myMovieTimeScale < GetMovieTimeScale(gSrcMovies[myMovieIter]))
  290.             myMovieTimeScale = GetMovieTimeScale(gSrcMovies[myMovieIter]);
  291.     }
  292.     
  293.     for (myMovieIter = 0; myMovieIter < gSpecCount; myMovieIter++) {
  294.         if (myMovieTimeScale != GetMovieTimeScale(gSrcMovies[myMovieIter]))
  295.             SetMovieTimeScale(gSrcMovies[myMovieIter], myMovieTimeScale);
  296.     }
  297.     
  298.     // the effect duration is the minimum of the length of the tracks
  299.     if (gSpecCount == 0)
  300.         myEffectDuration = myMovieTimeScale * 10;
  301.     else
  302.         myEffectDuration = GetTrackDuration(gSrcTracks[0]);
  303.     
  304.     for (myMovieIter = 1; myMovieIter < gSpecCount; myMovieIter++) {
  305.         if (myEffectDuration > GetTrackDuration(gSrcTracks[myMovieIter]))
  306.             myEffectDuration = GetTrackDuration(gSrcTracks[myMovieIter]);
  307.     }
  308.     
  309.     // default size when there are no video tracks
  310.     videoTrackFXWidth = 160L << 16;
  311.     videoTrackFXHeight = 120L << 16;
  312.  
  313.     for (myMovieIter = 0; myMovieIter < kMaxNumSources; myMovieIter++) {
  314.         videoTracks[myMovieIter] = NULL;
  315.     }
  316.     
  317.     // make the video tracks
  318.     for (myMovieIter = 0; myMovieIter < gSpecCount; myMovieIter++) {
  319.         Fixed    mySrcTrackWidth, mySrcTrackHeight;
  320.         OSType    mySrcMediaType = 0;
  321.         Media    videoMedia;
  322.  
  323.         // videoTracks[n] is a clone of gSrcTracks[n]
  324.         GetTrackDimensions(gSrcTracks[myMovieIter], &mySrcTrackWidth, &mySrcTrackHeight);
  325.         
  326.         if ((myMovieIter == 0) || (videoTrackFXWidth < mySrcTrackWidth))
  327.                 videoTrackFXWidth = mySrcTrackWidth;
  328.                 
  329.         if ((myMovieIter == 0) || (videoTrackFXHeight < mySrcTrackHeight))
  330.                 videoTrackFXHeight = mySrcTrackHeight;
  331.         
  332.         GetMediaHandlerDescription(GetTrackMedia(gSrcTracks[myMovieIter]), &mySrcMediaType, NULL, NULL);
  333.  
  334.         videoTracks[myMovieIter] = NewMovieTrack(myDestMovie, mySrcTrackWidth, mySrcTrackHeight, 0);
  335.         BailNil(videoTracks[myMovieIter]);
  336.         videoMedia = NewTrackMedia(videoTracks[myMovieIter], mySrcMediaType, myMovieTimeScale, NULL, 0);
  337.         BailNil(videoMedia);
  338.         
  339.         if (gCopyMovieMedia) {
  340.             myErr = BeginMediaEdits(videoMedia);
  341.             BailError(myErr);
  342.         }
  343.  
  344.         myErr = CopyTrackSettings(gSrcTracks[myMovieIter], videoTracks[myMovieIter]);
  345.         BailError(myErr);
  346.         myErr = InsertTrackSegment(gSrcTracks[myMovieIter], videoTracks[myMovieIter], 0, myEffectDuration, 0);
  347.         BailError(myErr);
  348.         
  349.         if (gCopyMovieMedia) {
  350.             myErr = EndMediaEdits(videoMedia);
  351.             BailError(myErr);
  352.         }
  353.     }
  354.     
  355.     {
  356.         // videoTrackFX is the special track that implements the effect
  357.         videoTrackFX = NewMovieTrack(myDestMovie, videoTrackFXWidth, videoTrackFXHeight, 0);
  358.         BailNil(videoTrackFX);
  359.         videoMediaFX = NewTrackMedia(videoTrackFX, VideoMediaType, myMovieTimeScale, NULL, 0);
  360.         BailNil(videoMediaFX);
  361.     }
  362.  
  363.     {
  364.         ImageDescriptionHandle        myDesc = NULL;
  365.  
  366. #if USES_MAKE_IMAGE_DESC_FOR_EFFECT
  367.         OSErr                        myErr = noErr;
  368.         
  369.         // create a new sample description
  370.         myErr = MakeImageDescriptionForEffect(myEffectCode, &myDesc);
  371.         if (myErr != noErr)
  372.             BailError(myErr);
  373. #else
  374.         // create a new sample description
  375.         myDesc = (ImageDescriptionHandle)NewHandleClear(sizeof(ImageDescription));
  376.         BailNil(myDesc);
  377.         
  378.         (**myDesc).idSize = sizeof(ImageDescription);
  379.         (**myDesc).cType = myEffectCode;
  380.         (**myDesc).hRes = 72L << 16;
  381.         (**myDesc).vRes = 72L << 16;
  382.         (**myDesc).dataSize = 0L;
  383.         (**myDesc).frameCount = 1;
  384.         (**myDesc).depth = 0;
  385.         (**myDesc).clutID = -1;
  386. #endif
  387.         // fill in the fields of the sample description
  388.         (**myDesc).vendor = kAppleManufacturer;
  389.         (**myDesc).temporalQuality = codecNormalQuality;
  390.         (**myDesc).spatialQuality = codecNormalQuality;
  391.         (**myDesc).width = videoTrackFXWidth >> 16;
  392.         (**myDesc).height = videoTrackFXHeight >> 16;
  393.         
  394.         // add effects sample to movie
  395.         myErr = BeginMediaEdits(videoMediaFX);
  396.         BailError(myErr);
  397.  
  398.         myErr = AddMediaSample(videoMediaFX, gEffectSample, 0, GetHandleSize(gEffectSample), myEffectDuration, (SampleDescriptionHandle)myDesc, 1, 0, &mySampleTime);
  399.         BailError(myErr);
  400.  
  401.         myErr = EndMediaEdits(videoMediaFX);
  402.         BailError(myErr);
  403.  
  404.         QTDisposeAtomContainer(gEffectSample);
  405.         DisposeHandle((Handle)myDesc);
  406.     }
  407.  
  408.     myErr = InsertMediaIntoTrack(videoTrackFX, 0, mySampleTime, myEffectDuration, fixed1);
  409.     BailError(myErr);
  410.  
  411.     // create and add the input map
  412.     {
  413.         long                myRefIndex1, myRefIndex2;
  414.         QTAtomContainer        myInputMap;
  415.         QTAtom                myInputAtom;
  416.         OSType                myInputType;
  417.         long                myLong;
  418.  
  419.         QTNewAtomContainer(&myInputMap);
  420.  
  421.         // first input
  422.         if (videoTracks[0]) {
  423.             AddTrackReference(videoTrackFX, videoTracks[0], kTrackModifierReference, &myRefIndex1);
  424.             QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex1, 0, 0, NULL, &myInputAtom);
  425.     
  426.             myInputType = EndianU32_NtoB(kTrackModifierTypeImage);
  427.             QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL);
  428.     
  429.             myLong = EndianU32_NtoB(kSourceOneName);
  430.             QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL);
  431.         }
  432.  
  433.         // second input
  434.         if (videoTracks[1]) {
  435.             AddTrackReference(videoTrackFX, videoTracks[1], kTrackModifierReference, &myRefIndex2);
  436.             QTInsertChild(myInputMap, kParentAtomIsContainer, kTrackModifierInput, myRefIndex2, 0, 0, NULL, &myInputAtom);
  437.     
  438.             myInputType = EndianU32_NtoB(kTrackModifierTypeImage);
  439.             QTInsertChild(myInputMap, myInputAtom, kTrackModifierType, 1, 0, sizeof(myInputType), &myInputType, NULL);
  440.     
  441.             myLong = EndianU32_NtoB(kSourceTwoName);
  442.             QTInsertChild(myInputMap, myInputAtom, kEffectDataSourceType, 1, 0, sizeof(myLong), &myLong, NULL);
  443.         }
  444.  
  445.         // set that map
  446.         if (gSpecCount > 0)
  447.             SetMediaInputMap(GetTrackMedia(videoTrackFX), myInputMap);
  448.         
  449.         QTDisposeAtomContainer(myInputMap);
  450.     }
  451.  
  452.     myErr = AddMovieResource(myDestMovie, myMovieRefNum, &myResID, "\pMovie 1");
  453.     BailError(myErr);
  454.     
  455.     CloseMovieFile(myMovieRefNum);
  456.     
  457.     for (myMovieIter = 0; myMovieIter < gSpecCount; myMovieIter++)
  458.         DisposeMovie(gSrcMovies[myMovieIter]);
  459.         
  460.     DisposeMovie(myDestMovie);
  461.     
  462. bail:
  463.     return;
  464. }
  465.  
  466.  
  467. #if TARGET_OS_WIN32
  468. //////////
  469. //
  470. // QTEffects_EffectsDialogCallback
  471. // This function is called by QTML when it processes events for the standard or custom effects parameter dialog box.
  472. // 
  473. //////////
  474.  
  475. static void QTEffects_EffectsDialogCallback (EventRecord *theEvent, DialogRef theDialog, DialogItemIndex theItemHit)
  476. {
  477.     QTParamDialogEventRecord    myRecord;
  478.  
  479.     myRecord.theEvent = theEvent;
  480.     myRecord.whichDialog = theDialog;
  481.     myRecord.itemHit = theItemHit;
  482.  
  483.     if (gEffectsDialog != 0L) {
  484.         QTStandardParameterDialogDoAction(gEffectsDialog, pdActionModelessCallback, &myRecord);
  485.     
  486.         // see if the event is meant for the effects parameter dialog box
  487.         QTEffects_HandleEffectsDialogEvents(theEvent, theItemHit);
  488.     }
  489. }
  490.  
  491.  
  492. //////////
  493. //
  494. // QTEffects_CustomDialogWndProc
  495. // Handle messages for the custom effects parameters dialog box.
  496. // 
  497. //////////
  498.  
  499. LRESULT CALLBACK QTEffects_CustomDialogWndProc (HWND theWnd, UINT theMessage, UINT wParam, LONG lParam)
  500. {
  501.     EventRecord            myEvent = {0};
  502.  
  503.     if (!gDoneWithDialog && (theMessage == 0x7FFF))
  504.         QTEffects_EffectsDialogCallback(&myEvent, GetNativeWindowPort(theWnd), 0);
  505.  
  506.     return(DefWindowProc(theWnd, theMessage, wParam, lParam));
  507. }
  508. #endif
  509.  
  510.  
  511. //////////
  512. //
  513. // QTEffects_HandleEffectsDialogEvents
  514. // Process events that might be targeted at the standard effects parameter dialog box.
  515. // Return true if the event was completely handled.
  516. // 
  517. //////////
  518.  
  519. Boolean QTEffects_HandleEffectsDialogEvents (EventRecord *theEvent, DialogItemIndex theItemHit)
  520. {
  521.     Boolean            isHandled = false;
  522.     OSErr            myErr = noErr;
  523.     
  524.     // pass the event to the standard effects parameter dialog box handler
  525.     myErr = QTIsStandardParameterDialogEvent(theEvent, gEffectsDialog);
  526.     
  527.     // the result from QTIsStandardParameterDialogEvent tells us how to respond next
  528.     switch (myErr) {
  529.         
  530.         case codecParameterDialogConfirm:
  531.         case userCanceledErr:
  532.             // the user clicked the OK or Cancel button; dismiss the dialog box and respond accordingly
  533.             gDoneWithDialog = true;
  534.             QTStandardParameterDialogDoAction(gEffectsDialog, pdActionConfirmDialog, NULL);
  535.             QTDismissStandardParameterDialog(gEffectsDialog);
  536.             gEffectsDialog = 0L;
  537.             QTEffects_RespondToDialogSelection(myErr);
  538.             isHandled = true;
  539.             break;
  540.             
  541.         case noErr:
  542.             // the event was completely handled by QTIsStandardParameterDialogEvent
  543.             isHandled = true;
  544.             break;
  545.             
  546.         case featureUnsupported:
  547.             // the event was not handled by QTIsStandardParameterDialogEvent;
  548.             // let the event be processed normally
  549.             isHandled = false;
  550.             break;
  551.             
  552.         default:
  553.             // the event was not handled by QTIsStandardParameterDialogEvent;
  554.             // do not let the event be processed normally
  555.             isHandled = true;
  556.             break;
  557.     }
  558.  
  559.     return(isHandled);
  560. }
  561.  
  562.  
  563. //////////
  564. //
  565. // QTEffects_PromptUserForFilesAndMakeEffect
  566. // Let the user select some movies, then apply the effect to them.
  567. //
  568. // If the user cancels the first file-open dialog box, there are zero sources.
  569. // If the user cancels the second file-open dialog box, there is one source.
  570. // 
  571. //////////
  572.  
  573. void QTEffects_PromptUserForFilesAndMakeEffect (void)
  574. {
  575.     FSSpec        mySpecs[kMaxNumSources];
  576.     int            mySpecCount;
  577.     
  578.     // ask for up to kMaxNumSources movie files;
  579.     // accept early cancels; they just mean there are fewer input movies
  580.     mySpecCount = 0;
  581.     while (mySpecCount < kMaxNumSources) {
  582.         SFTypeList                myTypeList;
  583.         StandardFileReply        myReply;
  584.  
  585.         myTypeList[0] = MovieFileType;
  586.  
  587.         StandardGetFilePreview(NULL, 1, myTypeList, &myReply);
  588.         if (!myReply.sfGood)
  589.             break;    // the user doesn't want any more source movies
  590.     
  591.         // save the FSSpec from the reply information
  592.         mySpecs[mySpecCount] = myReply.sfFile;
  593.         
  594.         mySpecCount++;
  595.     }
  596.     
  597.     QTEffects_DisplayDialogForSources(mySpecs, mySpecCount);
  598. }
  599.